#ifndef NOEUDVISITOR_H_
#define NOEUDVISITOR_H_

#include <vector>
#include <iostream>
#include <iomanip>
using namespace std;

// declaration des Noeuds
class NoeudProg;
class NoeudSeqInst;
class NoeudSeqDecl;
class NoeudPour;
class NoeudSi;
class NoeudTantQue;
class NoeudRepeter;
class NoeudAffectation;
class NoeudAffectationPour;
class NoeudDeclaration;
class NoeudEcrire;
class NoeudLire;
class NoeudOperateurBinaire;
class SymboleValue;


/* Specification des metode visiteur qui permet d'evaluer
 *  une structure (Une metode pour chaque type de noeud */
/* Classe abstraite du visitor, mere de tout les visiteurs
 *  (afficher, evaluation, transphormation ...) */

//---------------------------------------------------------------
class NoeudVisitor { // Classe Abstraite
public:
    NoeudVisitor() {}
    virtual ~NoeudVisitor() {}
    virtual void VisitNoeudProg(NoeudProg*) {}
    virtual void VisitNoeudSeqInst(NoeudSeqInst*) {}
    virtual void VisitNoeudSeqDecl(NoeudSeqDecl*) {}
    virtual void VisitNoeudPour(NoeudPour*) {}
    virtual void VisitNoeudSi(NoeudSi*) {}
    virtual void VisitNoeudTantQue(NoeudTantQue*) {}
    virtual void VisitNoeudRepeter(NoeudRepeter*) {}
    virtual void VisitNoeudAffectation(NoeudAffectation*) {}
    virtual void VisitNoeudAffectationPour(NoeudAffectationPour*) {}
    virtual void VisitNoeudDeclaration(NoeudDeclaration*) {}
    virtual void VisitNoeudEcrire(NoeudEcrire*) {}
    virtual void VisitNoeudLire(NoeudLire*) {}
    virtual void VisitNoeudOperateurBinaire(NoeudOperateurBinaire*) {}
    virtual void VisitSymboleValue(SymboleValue*) {}
    virtual inline void IncresIndentation() { }
    virtual inline void DecresIndentation() { }
    virtual inline void IncresErreur() {}
    virtual inline int getErreur() {
        return 0;
    }
    virtual inline void afficherMotsCles(string) {}
    virtual inline void afficherLigne() { }
    virtual  void afficherType(string) {}
    virtual void afficherOp(string) {}

};

//---------------------------------------------------------------
class AfficherVisitor : public NoeudVisitor  {
public:
    AfficherVisitor();
    inline void afficherIndentation() {
        cout << setw(4*indentation) << " ";
    }
    inline void IncresIndentation() {
        indentation ++;
    }
    inline void DecresIndentation() {
        indentation --;
    }
    virtual void VisitNoeudProg(NoeudProg*);
    virtual void VisitNoeudSeqInst(NoeudSeqInst*);
    virtual void VisitNoeudSeqDecl(NoeudSeqDecl*);
    virtual void VisitNoeudPour(NoeudPour*);
    virtual void VisitNoeudSi(NoeudSi*);
    virtual void VisitNoeudTantQue(NoeudTantQue*);
    virtual void VisitNoeudRepeter(NoeudRepeter*);
    virtual void VisitNoeudAffectation(NoeudAffectation*);
    virtual void VisitNoeudAffectationPour(NoeudAffectationPour*);
    virtual void VisitNoeudDeclaration(NoeudDeclaration*);
    virtual void VisitNoeudEcrire(NoeudEcrire*);
    virtual void VisitNoeudLire(NoeudLire*);
    virtual void VisitNoeudOperateurBinaire(NoeudOperateurBinaire* e);
    virtual void VisitSymboleValue(SymboleValue*);
private:
    int indentation;
};

//---------------------------------------------------------------
class TypeVisitor : public NoeudVisitor  {
public:
    TypeVisitor();
    virtual void VisitNoeudProg(NoeudProg*);
    virtual void VisitNoeudSeqInst(NoeudSeqInst*);
    virtual void VisitNoeudSeqDecl(NoeudSeqDecl*);
    virtual void VisitNoeudPour(NoeudPour*);
    virtual void VisitNoeudSi(NoeudSi*);
    virtual void VisitNoeudTantQue(NoeudTantQue*);
    virtual void VisitNoeudRepeter(NoeudRepeter*);
    virtual void VisitNoeudAffectation(NoeudAffectation*);
    virtual void VisitNoeudAffectationPour(NoeudAffectationPour*);
    virtual void VisitNoeudDeclaration(NoeudDeclaration*);
    virtual void VisitNoeudEcrire(NoeudEcrire*);
    virtual void VisitNoeudLire(NoeudLire*);
    virtual void VisitNoeudOperateurBinaire(NoeudOperateurBinaire* e);
    virtual void VisitSymboleValue(SymboleValue*);
    inline void IncresErreur() {
        nbErreur++;
    }
    inline int getErreur() {
        return nbErreur;
    }
    void erreurTypage (NoeudOperateurBinaire* e, string mess);
    void erreurTypAffect(NoeudAffectation* e, string mess);

private:
    int nbErreur;
};

//---------------------------------------------------------------
class ConversionVisitor : public NoeudVisitor  { // Conversion en C++
public:
    ConversionVisitor();
    virtual void afficherIndentation() {
        cout << setw(4*indentation) << " ";
    }
    inline void IncresIndentation() {
        indentation ++;
    }
    inline void DecresIndentation() {
        indentation --;
    }
    virtual void VisitNoeudProg(NoeudProg*);
    virtual void VisitNoeudSeqInst(NoeudSeqInst*);
    virtual void VisitNoeudSeqDecl(NoeudSeqDecl*);
    virtual void VisitNoeudPour(NoeudPour*);
    virtual void VisitNoeudSi(NoeudSi*);
    virtual void VisitNoeudTantQue(NoeudTantQue*);
    virtual void VisitNoeudRepeter(NoeudRepeter*);
    virtual void VisitNoeudAffectation(NoeudAffectation*);
    virtual void VisitNoeudAffectationPour(NoeudAffectationPour*);
    virtual void VisitNoeudDeclaration(NoeudDeclaration*);
    virtual void VisitNoeudEcrire(NoeudEcrire*);
    virtual void VisitNoeudLire(NoeudLire*);
    virtual void VisitNoeudOperateurBinaire(NoeudOperateurBinaire* e);
    virtual void VisitSymboleValue(SymboleValue*);
    inline void afficherMotsCles(string mc) {
        cout << mc;
    }
    inline void afficherLigne() {
        cout << endl;
        afficherIndentation();
    }
    void afficherType(string type);
    void afficherOp(string op);

private:
    int indentation;
};

#endif
